package org.angelica.utils.weixin;

import com.fasterxml.jackson.databind.JsonNode;
import org.angelica.utils.common.ToolUtil;
import org.angelica.utils.json.JacksonUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.apache.http.protocol.HTTP;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.InputStream;
import java.security.Security;

/**
 * 微信rest api 封装
 * @author aiken
 *
 */
public class WeixinUtil {

    private static final Logger logger = LoggerFactory.getLogger(WeixinUtil.class);

    /**
	 * 通过code获取openid和session_key
	 * @param appid
	 * @param secret
	 * @param jsCode
	 * @return
	 */
	public static String jscode2session(String appid,String secret,String jsCode) {
		try {
			String result = Request.Get("https://api.weixin.qq.com/sns/jscode2session?appid="+appid+"&secret="+secret+"&js_code="+jsCode+"&grant_type=authorization_code")
				.execute().returnContent().asString();
            logger.info("jscode2session:"+result);
			return result;
		} catch (IOException e) {
            logger.error(ToolUtil.getExceptionMsg(e));
		}
		return null;
	}


    public static boolean initialized = false;

    /**
     * 初始化AES加密解密提供者
     */
    public static void initializeBouncyCastleProvider() {
        if (initialized) {
            return;
        }
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    /**
     * 解析unionid
     * @param sessionKey
     * @param rawData
     * @param signature
     * @param encryptedData
     * @param iv
     * @return
     */
	public static String encodeUserInfo(String sessionKey,String rawData,String signature,String encryptedData,String iv){

	    if(signature.equals(DigestUtils.sha1Hex(rawData+sessionKey))){

            //被加密的数据
            byte[] dataByte = Base64.decodeBase64(encryptedData);
            //加密秘钥
            byte[] keyByte = Base64.decodeBase64(sessionKey);
            //偏移量
            byte[] ivByte = Base64.decodeBase64(iv);
            try {

                initializeBouncyCastleProvider();

                IvParameterSpec ivParameterSpec = new IvParameterSpec(ivByte);
                SecretKeySpec skeySpec = new SecretKeySpec(keyByte, "AES");
                Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
                cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);

                byte[] resultByte = cipher.doFinal(dataByte);
                if (null != resultByte && resultByte.length > 0) {
                    return new String(resultByte);
                }
                return null;
            } catch (Exception e) {
                logger.error(ToolUtil.getExceptionMsg(e));
            }
        }
        logger.error("微信解密签名错误：signature={},session_key={},rawData={},encryptedData={},iv={}",signature,sessionKey,rawData,encryptedData,iv);
	    return null;
    }

    /**
     * 解析微信群ID
     * @param sessionKey
     * @param encryptedData
     * @param iv
     * @return
     */
    public static String encodeOpengid(String sessionKey,String encryptedData,String iv){
        //被加密的数据
        byte[] dataByte = Base64.decodeBase64(encryptedData);
        //加密秘钥
        byte[] keyByte = Base64.decodeBase64(sessionKey);
        //偏移量
        byte[] ivByte = Base64.decodeBase64(iv);
        try {

            initializeBouncyCastleProvider();

            IvParameterSpec ivParameterSpec = new IvParameterSpec(ivByte);
            SecretKeySpec skeySpec = new SecretKeySpec(keyByte, "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);

            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                return new String(resultByte);
            }

        } catch (Exception e) {
            logger.error(ToolUtil.getExceptionMsg(e));
        }
        return null;
    }


    /**
     * 获取小程序的access_token
     * https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
     * @param appid
     * @param secret
     * @return
     */
    public static String getMpAccessToken(String appid,String secret) {
        try {
            String result = Request.Get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret)
                    .execute().returnContent().asString();
            return result;
        } catch (IOException e) {
            logger.error(ToolUtil.getExceptionMsg(e));
        }
        return null;
    }


    /**
     * 发送小程序模板消息
     * @param accessToken
     * @param touser
     * @param templateId
     * @param page
     * @param formId
     * @param data
     */
    public static void sendTemplateMessage(String accessToken, String touser, String templateId, String page, String formId, String data) {
        try {
            StringBuilder params = new StringBuilder();
            params.append("{");
            params.append("   \"touser\": \""+touser+"\",");
            params.append("   \"template_id\": \""+templateId+"\",");
            if(StringUtils.isNotBlank(page)){
                params.append("   \"page\": \""+page+"\",");
            }
            params.append("   \"form_id\": \""+formId+"\",");
            params.append("   \"data\": "+data);
            params.append("}");

            String result = Request.Post("https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token="+accessToken)
                    .bodyString(params.toString(), ContentType.APPLICATION_JSON)
                    .execute().returnContent().asString();
            JsonNode jsonNode = JacksonUtil.nonDefaultMapper().getJsonNode(result);
            int errcode = jsonNode.get("errcode").asInt();
            String errmsg = jsonNode.get("errmsg").asText();
            if(errcode != 0){
                logger.error("发送模板消息失败：errcode:{},errmsg:{},params:{}",errcode,errmsg,params.toString());
            }
        } catch (IOException e) {
            logger.error(ToolUtil.getExceptionMsg(e));
        }
    }

    /**
     * 获取小程序二维码
     * @param accessToken
     * @param scene
     * @param page
     * @return
     */
    public static InputStream getwxacodeunlimit(String accessToken,String scene,String page){
        try {
            StringBuilder params = new StringBuilder();
            params.append("{");
            params.append("   \"scene\": \""+scene+"\",");
            params.append("   \"page\": \""+page+"\",");
            params.append("   \"width\": "+300);
            params.append("}");

            InputStream result = Request.Post("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+accessToken)
                    .addHeader(HTTP.CONTENT_TYPE,"application/json")
                    .bodyString(params.toString(), ContentType.IMAGE_JPEG)
                    .execute().returnContent().asStream();
            return result;
        } catch (IOException e) {
            logger.error(ToolUtil.getExceptionMsg(e));
        }
        return null;
    }

    public static void main(String[] args){
        String sessionKey = "qLO+TJIKPooRsJGgqfyvEA==";
        String rawData = "{\"nickName\":\"小卡卡\",\"gender\":0,\"language\":\"zh_CN\",\"city\":\"\",\"province\":\"\",\"country\":\"\",\"avatarUrl\":\"https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTK3HYBtyedLicK1blxiaYabeOKpibLxbCBY8jfH9X6N6JZAibg8GlQvEgFmPU7W9FmjTCN4RG5UjS9dkQ/132\"}";
        String signature = "f8cb13384ae9eb72fe137e14d4c2e4505ba37b5c";
        String encryptedData = "za80kzhdj/BS7SmDvJTFsAp4XSA1Bcz6Gs8mHWEKHROPrLdOyloSgVi/PeMuO5xGojOWL9U0R4f9c3LaQc2pguvyGiv27Ng/8sV0WOodc3esUCXkIRGgtRgI8qAvfR2SawPh4aeoblBqVXpcRpK1MTj5gkAkPoxJ7XNik92iYjnwyZQe1bb9dU4GvBluW8U6h6sdWnZZ/XX7Dz+CSsV22VJncwGXfsLk6iUGs9WThhcCmjVxuh6vxLGBN6z7ZuRRldDxAbIGB0rUJsFKLd/hdbxcDH0f5jzKSLbIPake0BOsS6+LpyfdvjQic0VaymX0UIAA8phfH66KVu3ugyv20T1+gXztzLX/H0dLo/nzGASbhVpYwmU4J/HZkKbxEqXI65nq+RoBh7l8J9YtegkEGDWXEssuHS+pfjcBZMgpFW8lkz1oa5TQdzLxi5UHTY2kPh0F6MRiF/O4U4NiqYjlRVVhe/AWYJ/IwP7TNGFogs/8Z6MqCfxXUemEw/OdDxoE";
        String iv = "XR20GAGDdamzIcQUR3TAGQ==";
        String result = WeixinUtil.encodeUserInfo(sessionKey,rawData,signature,encryptedData,iv);
        System.out.print(result);
//        String accessToken = WeixinUtil.getMpAccessToken("wxfd5964ad26e5ca29","90349ae963ce75e646c2e802407567c7");
//        WeixinUtil.getwxacodeunlimit(accessToken,"1","/pages/course/course");
	}
}
